home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-07
/
book.exe
/
LANRES.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-22
|
17KB
|
664 lines
/*
// LANRES.C Memory resident functions for LAN information utility
//
// (c) Copyright 1990, 1991 Adrian King.
//
//
// This code was developed for inclusion in the book
// "Running LANtastic", by Adrian King, published by
// Bantam Books, October 1991.
//
// This product uses the TesSeRact(tm) Ram-Resident Library and
// supports the TesSeRact Standard for Ram-Resident Program Comm-
// unication. For information about TesSeRact, contact the TesSeRact
// Development Team at:
//
// TesSeRact Development Team
// 1657 The Fairways
// Suite 101
// Jenkintown PA 19046
// 1-215-884-3373
//
// Compuserve: 70731,20
// MCIMAIL: 315-5415
//
// This is the main module for the memory resident piece. It turns
// itself into a memory resident program and then waits for network
// messages. Some messages elicit a response, others cause a message
// to be popped up on the screen.
//
// Run the program with the three optional switches: BOOT, POP or BEEP.
// For example:
//
// lanres /boot=n /pop=n /beep=y
//
// Will disable remote booting, turn off message popup and leave message
// arrival beeping on. The default is: /boot=y /pop=y /beep=y.
//
// This program can be removed from memory by typing Alt+L.
//
// Make sure to compile this program with a -DBACKGROUND switch.
//
// $Header: C:/USR/LANBOOK/SRC2/LAN/VCS/LANRES.C_V 1.2 22 Sep 1991 9:16:52 $
//
// $Log: C:/USR/LANBOOK/SRC2/LAN/VCS/LANRES.C_V $
//
// Rev 1.2 22 Sep 1991 9:16:52
//Added correct TesSeRact copyright notice.
//Cleaned up some comments.
//
// Rev 1.1 29 Aug 1991 12:37:30
//Modified delay in replying to status messages to avoid message
//collisions at receiver. Delay is calculated as a random number
//(derived from the node name.) This seems to remove most of the
//collisions.
//
// Rev 1.0 13 Jul 1991 11:19:54
//Initial revision.
//
*/
// Standard includes
#include "string.h"
#include "dos.h"
// Local includes
#include "nos.h"
#include "noslib.h"
#include "lan.h"
// Includes needed for the interface to TesSeRact
#include "tess.h"
// Declarations to interface with assembler module (NOSIF.ASM)
extern void far nowhere(); // Null routine in NOSIF.ASM
FARPROC oldservice = nowhere; // Holds address of previous message service
// handler. Calls null routine until set up.
FARPROC olddos = nowhere; // Holds address of previous DOS service
// vector. Null call until set up.
extern void far msg_interrupt();// Routines in NOSIF.ASM called by NOS
FARPROC msg_service = msg_interrupt;
extern void far nos_interrupt();
FARPROC dos_service = nos_interrupt;
extern void far msg_proc();
FARPROC fpmsg_proc = msg_proc;
extern void far dowork();
FARPROC fpdowork = dowork;
extern WORD bworktodo; // Incremented when dowork() must be called
// Decremented after work is done
// Global declarations for this module
#ifdef __TURBOC__
unsigned _heaplen = 1024; // Limit heap to 1K
unsigned _stklen = 2048; // Limit stack length to 2K
#endif
struct workq workq[D_WORKITEMS];// Queue of work to be done
BOOL bBootflag = TRUE; // Allow remote reboot, FALSE disallows
BOOL bPopflag = FALSE; // Disallow message popup, TRUE allows
BOOL bBeepflag = FALSE; // Message arrival beep, FALSE disallows
BOOL bQuietflag = FALSE; // Quiet at shut down, FALSE means quiet
char cpMachine[D_NAMESZ]; // Name of this node
char cpOther[D_NAMESZ]; // Name of other machine
int nMsgflag; // Old message flag
unsigned nReplydelay = 0; // Pseudo random # for replay delay
struct msgstats msgstats = { 0, 0, 0, 0, 0};
// Forward declarations
void parsecmd(); // Analyze command arguments
void help(); // Print help and quit
void far msg_proc(); // Routine called to process messages
extern void far reboot(); // Reboot function
//
// TSRMAIN
//
// This routine is called when the popup key combination is hit.
// (Alt+L). It prints some stats, resets all the NOS vectors and
// unloads the program.
//
void far pascal TsrMain()
{
int i;
if (bQuietflag){
NOSprintstr("\n\nLANRES status on ");
NOSprintstr(lannode[0].cpName);
NOSprintstr("\n\n");
NOSprintstr("\nReceived 0x");
NOSprintx(msgstats.in);
NOSprintstr(" messages.\nSent 0x");
NOSprintx(msgstats.out);
NOSprintstr(" messages.\nMessage service busy 0x");
NOSprintx(msgstats.msgbusy);
NOSprintstr(" times.\nReceived 0x");
NOSprintx(msgstats.statusack);
NOSprintstr(" status ack messages.\nReceived 0x");
NOSprintx(msgstats.unknown);
NOSprintstr(" unidentifiable messages.\n\n");
NOSprintstr("Machines active on the network:\n");
for (i = 0; i < D_NODES; i++){
if (lannode[i].cpName[0] != '\0'){
NOSprintstr(lannode[i].cpName);
NOSprintstr(", flags = 0x");
NOSprintx(lannode[i].wFlags);
NOSprintstr("\n");
}
}
NOSprintstr("Unloading...\n");
}
(void)NOSSetMsgFlag(nMsgflag); // Reset message flag and service
(void)NOSSetMsgVector(oldservice); // vectors.
(void)NOSSetDOSVector(olddos);
TsRelease(TSRid); // Release this TSR from memory
}
//
// TSRUSERPROC
//
// Called (via TesSeRact) from the foreground program.
// The call is either to clear the node table (prior to
// asking the network nodes for an update), or a request
// for the updated table. In the first case the parameter is 0.
// Otherwise the parameter is the address of entry 1 in the network
// node table. Entries 1 through D_NODES-1 from the background
// table are copied to this address.
//
void far pascal TsrUserProc(fpN)
void far *fpN;
{
char far *fp = (char far *)fpN;
char *cpN = (char *)&lannode[1];
int i;
if (fpN == (void far *)0){
for (i = 1; i < D_NODES; i++)
lannode[i].cpName[0] = '\0';
} else {
for (i = (D_NODES - 1) * sizeof (struct lannode); i > 0; i--)
*fp++ = *cpN++;
}
}
//
// MAIN
//
void main(argc, argv)
int argc;
char *argv[];
{
int i;
BOOL bSet;
int n;
char *cp;
NOSprintstr("LANRES version 1.0 - (C) Copyright 1991 Adrian King\n");
// Check to see if we are already loaded, and
// abort if so
if (TsCheckResident((char far *)TSRIdStr, (unsigned far *)&TSRid)
== 0xFFFF){
// Already loaded
TsRestore2f();
FATAL(E_LANLIBL);
}
// Parse command arguments
if (argc != 1)
for (i = 1; i < argc; i++)
parsecmd(argv[i]);
if ((i = NOSPresence())== -1) // Test for some part of NOS loaded
FATAL(E_NONOS);
initnodetable(); // Set up network node table
// Get name of this node
if (NOSGetMachineName(cpMachine, &n, &bSet) == -1)
FATAL(E_GETNAME);
if (!bSet)
FATAL(E_NONAME);
cp = strchr(cpMachine, ' ');
if (cp != (char *)0)
*cp = '\0'; // Null terminate the name
// Make it entry 0 in the table
addname(cpMachine, i);
// Calculate the status message reply
// delay based on this node's network
// name. See dowork() for more info.
for (n = 0; n < strlen(cpMachine); n++)
nReplydelay += cpMachine[n];
nReplydelay *= 3;
initwork(); // Set up work queue
// Get and save message service vector
if (NOSGetMsgVector(&oldservice) == -1)
FATAL(E_GETMSGVEC);
NOSGetMsgFlag(&nMsgflag); // Save message service flag
//
// Set message processing flag so that delivery to message
// service occurs. If beeping was off, keep it off. Otherwise
// set it to what the bBeepflag says. NOTE: By default, beeping
// is OFF.
//
// If popup was off, keep it off. Otherwise set it to what
// bPopflag says.
//
i = MPB_deliver;
if (bBeepflag)
i |= (nMsgflag & MPB_beep);
if (bPopflag)
i |= (nMsgflag & MPB_auto_pop_up);
if (NOSSetMsgFlag(i) == -1)
FATAL(E_SETMSGFLAG);
// Save and set DOS service vector
if (NOSGetDOSVector(&olddos) == -1)
FATAL(E_GETDOSVEC);
if (NOSSetDOSVector(dos_service) == -1)
FATAL(E_SETDOSVEC);
// Set address of our message service
if (NOSSetMsgVector(msg_service) == -1)
FATAL(E_SETMSGVEC);
//
// Go resident. Alt+L will unload the program.
//
i = SizeOfCode();
if (TsDoInit(TSRHOT_L,
TSRPOPALT,
TSRUSEPOPUP+TSRUSEUSER+NOPOPGRAPH,
i)
){
// Error trying to go resident
FATAL(E_GORES);
}
}
//
// INITWORK
//
// Initialize work queue. Called once from main().
//
void initwork()
{
int i;
for (i = 0; i < D_WORKITEMS; i++)
freework(&workq[i]);
}
//
// FREEWORK
//
// Free an entry in the work queue
//
void freework(cpW)
struct workq *cpW;
{
entercrit();
cpW->wType = 0;
leavecrit();
}
//
// NEXTWORK
//
// Get next work item in the work queue. Returns 0 if there
// is nothing there.
//
struct workq *nextwork()
{
int i;
entercrit();
for (i = 0; i < D_WORKITEMS; i++){
if (workq[i].wType != 0){
leavecrit();
return(&workq[i]);
}
}
leavecrit();
return (struct workq *)0;
}
//
// ALLOCWORK
//
// Allocate an empty work queue item. Returns 0 if none are
// available.
//
struct workq *allocwork()
{
int i;
entercrit();
for (i = 0; i < D_WORKITEMS; i++){
if (workq[i].wType == 0){
workq[i].wType = -1;
leavecrit();
return (&workq[i]);
}
}
leavecrit();
return (struct workq *)0;
}
//
// MSG_PROC
//
// Private message processing service
//
// This routine is called from the assembler msg_interrupt
// (in NOSIF.ASM). It either acts on the message or queues
// up a work item to be processed by dowork() later.
//
// If the work queue is full, then the message will be lost.
//
void far msg_proc(fpMsg)
struct message_buffer far *fpMsg;
{
struct workq *cpWork; // Points to workq item in use
int n;
char cpN[D_NAMESZ];
int nMsgtype;
msgstats.in++; // Update count of msgs received
// Copy in sender's name
copyfartonear(fpMsg->MB_originator, cpN, D_NAMESZ);
nMsgtype = fpMsg->MB_type;
switch (nMsgtype){
case MBT_LANstatusack: // Response to status enquiry
msgstats.statusack++;
// Build flags word
n = D_lanbios;
n |= (fpMsg->MB_text[1] == 'R')?D_redir:0;
n |= (fpMsg->MB_text[2] == 'S')?D_server:0;
n |= (fpMsg->MB_text[3] == 'L')?D_lanpup:0;
// Add name of responder to table
if (addname(cpN, n) != 0)
NOSprintstr("msg_proc(): error adding node name\n");
return;
case MBT_LANstatus: // Request for status
case MBT_LANsend: // Broadcast message
// Ignore if from self
if (nodenamecmp(lannode[0].cpName, cpN)==0)
return;
case MBT_LANtext: // Plain text message
case MBT_LANbootack: // Acknowledgement of boot request
case MBT_LANbootden: // Denial of boot request
case MBT_LANwarmboot: // Warm boot this machine
case MBT_LANcoldboot: // Cold boot this machine
default: // Collects normal NOS messages
//
// Allocate a workq entry. If none are available then lose
// the message.
//
cpWork = allocwork();
if (cpWork == (struct workq *)0){
msgstats.msgbusy++;
return;
}
// Copy in the msg and its type
copyfartonear((char far *)fpMsg, (char *)&cpWork->M,
sizeof(struct message_buffer));
cpWork->wType = nMsgtype;
bworktodo++; // Show there is work to be done
return;
};
}
//
// DOWORK
//
// Called from NOSIF.ASM when LANtastic calls the DOS service vector
// and the bworktodo flag is set to show that there is some work to
// be done.
//
// When this routine is called then it is safe to call DOS itself.
// However, NOTHING is set up that enables you to do so. The PSP is
// wrong, the stack is not yours, etc etc. Calling NOS routines is
// okay because the NOS sets itself up properly. Unless you do extra
// work, you cannot make INT 21H calls (for example.)
//
void far dowork()
{
int n;
char *cp1, *cp2;
struct workq *cpWork; // Points to work queue entry
while (bworktodo){
cpWork = nextwork(); // Pick up work queue entry pointer
// Return if null - "shouldn't happen"
if (cpWork == (struct workq *)0){
return;
}
switch (cpWork->wType){
case MBT_LANstatus: // Request for status, respond with
// what is loaded on this node plus
// its name.
gennrsl();
cp1 = cpWork->M.MB_text;// Address of message data area
for (n = 0; n < 4; n++)
*cp1++ = cpNRSL[n];
cp2 = " active on ";
while ((*cp1 = *cp2) != '\0'){
cp1++;
cp2++;
}
for (n = 0; n < D_NAMESZ; n++)
*cp1++ = lannode[0].cpName[n];
//
// NOS only buffers one message. A network status
// enquiry may cause many replies. Some will get lost
// due to collisions at the receiver. So, we delay the
// response according to the pseudo random number
// calculated as a function of the machine's
// name. This helps overcome message collisions at
// the receiver. Obviously this is not reliable.
//
delay(nReplydelay);
if (sendmessage(&(cpWork->M), cpWork->M.MB_originator,
MBT_LANstatusack, (char *)0, -1) == -1)
NOSprintstr("dowork() error responding to MBT_LANstatus\n");
break;
case MBT_LANwarmboot: // Boot this machine
case MBT_LANcoldboot:
// Send acknowledgement or denial
if (bBootflag)
cp1 = "Reboot request acknowledged";
else
cp1 = "Reboot request rejected";
// Don't acknowledge if the request
// came from this machine
if (nodenamecmp(lannode[0].cpName,
&(cpWork->M.MB_originator))!=0)
if (sendmessage(&(cpWork->M), cpWork->M.MB_originator,
MBT_LANbootack, cp1, strlen(cp1)) == -1)
NOSprintstr("dowork() error responding to boot\n");
if (bBootflag){
// Put up a message
// BUG: Might be wrong message
NOSPopUpMsg(D_DISPTICKS, D_DISPLINE);
// Reboot
if (cpWork->wType == MBT_LANwarmboot)
reboot(WARMBOOT);
else
reboot(COLDBOOT);
}
break;
case MBT_LANstatusack:
case MBT_LANtext: // Display text message
case MBT_LANsend: // Broadcast message
case MBT_LANbootack:
case MBT_general:
// Display the last message.
// BUG: may not be the last one held
// by NOS
NOSPopUpMsg(D_DISPTICKS, D_DISPLINE);
break;
default:
msgstats.unknown++; // Got a bad message type
break;
}
freework(cpWork); // Release work queue item
entercrit(); // Protect flag update
if (bworktodo)
bworktodo--; // Decrement work flag
leavecrit();
}
}
//
// PARSECMD
//
// Parse command arguments and set flags accordingly
// Exit with a help message if argument is unknown.
//
// Valid switches are:
//
// /BOOT=
// /POP=
// /BEEP=
//
// Followed by 'Yes' or 'No' (only 'y', 'Y', 'n' or 'N' are checked)
//
void parsecmd(s)
char *s;
{
struct cmdswitch {
char *cpId; // Command switch id
BOOL *pbFlag; // Pointer to related flag
};
#define Nswitches 4
struct cmdswitch cmdswitch[] = {"/BOOT=", &bBootflag,
"/BEEP=", &bBeepflag,
"/POP=" , &bPopflag,
"/VERBOSE=", &bQuietflag
};
int i, j;
// Search switch table for match
for (i = 0; i < Nswitches; i++){
// Length of string to match
j = strlen(cmdswitch[i].cpId);
if (strnicmp(s, cmdswitch[i].cpId, j) == 0){
if (s[j] == 'y' || s[j] == 'Y'){
*cmdswitch[i].pbFlag = TRUE;
return;
}
if (s[j] == 'n' || s[j] == 'N'){
*cmdswitch[i].pbFlag = FALSE;
return;
}
}
}
// Couldn't identify this switch, or syntax incorrect
help();
}
//
// HELP
//
// Print a help message and exit
//
void help()
{
NOSprintstr("\n\
Available command switches for LANRES are:\n\n\
/BOOT=[Yes|No] Allow or disallow remote booting\n\
/POP=[Yes|No] Allow or disallow message popup\n\
/BEEP=[Yes|No] Allow or disallow message arrival beeping\n\
/VERBOSE=[Yes|No] Show status messages when exiting\n\
");
// Exit - okay to call since we are not yet resident
#ifdef __TURBOC__
_exit(0);
#endif
#ifndef __TURBOC__
exit(0);
#endif
}